package fr.pud.client.view;

import java.awt.Container;
import java.awt.Toolkit;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;

import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JProgressBar;
import javax.swing.SwingWorker;

import org.openstreetmap.gui.jmapviewer.Coordinate;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;

import fr.pud.client.i18n.LanguagesConstants;
import fr.pud.client.model.PUDStation;
import fr.pud.client.model.PUDStationDatabase;
import fr.pud.client.model.Route;
import fr.pud.client.model.Routes;
import fr.pud.utils.DOMParser;

/**
 * Apr 9, 2012 - Projet_Ose.
 * @author Simon Devineau, Adrien Hierry, Leopold Houdin, Pierre Reliquet
 *         Ecole des Mines de Nantes
 *         SWReadingXML.java
 *         The swing worker which enables to read the xml file and to show a
 *         progress
 *         bar during the loading.
 */
public class SWReadingXML extends SwingWorker<String, Object> {
    private String         path;
    private XMLProgressBar progressFrame;
    private double         step;
    private double         progress;

    public SWReadingXML(String path) {
        MainFrame.getMainFrame().setVisible(false);
        MainFrame.getMainFrame().setEnabled(false);
        this.path = path;
        this.progressFrame = new XMLProgressBar();
        this.addPropertyChangeListener(new PropertyChangeListener() {
            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                if ("progress".equals(evt.getPropertyName())) {
                    SWReadingXML.this.progressFrame.getProgressBar().setValue(
                            (Integer) evt.getNewValue());
                    SWReadingXML.this.progressFrame.getProgressBar().setString(
                            LanguagesConstants.LANGUAGE
                                    .getString(LanguagesConstants.PROGRESS)
                                    + ": " + evt.getNewValue() + "%");
                }
            }
        });
    }

    /**
     * @return an ArrayList<ArrayList<Coordinate>> which represents the
     *         different routes
     */
    @Override
    protected String doInBackground() throws Exception {
        this.parseResultFile(this.path);
        return "";
    }

    /**
     * The action realized when the file has been read.
     */
    @Override
    protected void done() {
        try {
            this.setProgress(100);
            this.progressFrame.dispose();
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        MainFrame.getMainFrame().setVisible(true);
        MainFrame.getMainFrame().setEnabled(true);
    }

    /**
     * The method to parse a result file and get the routes
     * @param path
     *            , the path of the file
     * @return an ArrayList<ArrayList<Coordinate>> which represents the routes
     */
    public void parseResultFile(String path) {
        ArrayList<ArrayList<Integer>> node_ids = new ArrayList<ArrayList<Integer>>();
        ArrayList<ArrayList<Integer>> location_ids = new ArrayList<ArrayList<Integer>>();
        Document xml = DOMParser.getDOMTree(path, !DOMParser.VALIDATOR);
        /*
         * Getting the node_id
         */
        NodeList nodes = DOMParser.xPath(xml, "//route");
        this.step = 10.0 / nodes.getLength();
        this.progress = 0;
        for (int i = 0; i < nodes.getLength(); i++) {
            node_ids.add(new ArrayList<Integer>());
            NodeList stops = DOMParser.xPath(xml, "//route[" + (i + 1)
                    + "]/stops/*");
            for (int j = 0; j < stops.getLength(); j++) {
                node_ids.get(i).add(
                        Integer.parseInt(stops.item(j).getTextContent()));
            }
            this.progress += this.step;
            this.setProgress((int) this.progress);
        }
        /*
         * Getting location_id
         */
        this.step = 20.0 / nodes.getLength();
        for (ArrayList<Integer> list : node_ids) {
            ArrayList<Integer> subList = new ArrayList<Integer>();
            for (Integer i : list) {
                Number location = DOMParser.xPathNumber(xml, "//node[./id=" + i
                        + "]/location_id/text()");
                subList.add(location.intValue());
            }
            location_ids.add(subList);
            this.progress += this.step;
            this.setProgress((int) this.progress);
        }
        /*
         * Getting the coordinate
         */
        this.step = 70.0 / nodes.getLength();
        for (ArrayList<Integer> list : location_ids) {
            Route r = new Route();
            for (Integer i : list) {
                Number latitude = DOMParser.xPathNumber(xml, "//location[./id="
                        + i + "]/latitude/text()");
                Number longitude = DOMParser.xPathNumber(xml,
                        "//location[./id=" + i + "]/longitude/text()");
                Coordinate c = new Coordinate(latitude.doubleValue(),
                        longitude.doubleValue());
                // If the address is already in the database, nominatim is not
                // used
                PUDStation station = PUDStationDatabase.getInstance()
                        .getStation(c);
                if (station == PUDStationDatabase.NO_STATION) {
                    r.add(new PUDStation(c));
                }
                else {
                    r.add(station);
                }
            }
            Routes.getInstance().add(r);
            this.progress += this.step;
            this.setProgress((int) this.progress);
        }
    }
}

/**
 * Apr 9, 2012 - Projet_Ose.
 * @author Simon Devineau, Adrien Hierry, Leopold Houdin, Pierre Reliquet
 *         Ecole des Mines de Nantes
 *         SWReadingXML.java
 *         The progress bar which corresponds to the xml reading
 */
class XMLProgressBar extends JFrame {
    private static final long serialVersionUID = 4554161368991122131L;
    private JProgressBar      progressBar;
    private JLabel            label            = new JLabel(
                                                       LanguagesConstants.LANGUAGE
                                                               .getString(LanguagesConstants.XML_READING_DESCRIPTION));
    private Container         pane;

    public XMLProgressBar() {
        super();
        this.pane = this.getContentPane();
        this.pane.setLayout(new BoxLayout(this.pane, BoxLayout.PAGE_AXIS));
        this.pane.add(this.label);
        this.prepareProgressBar();
        this.setVisible(true);
        this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        this.pack();
        this.placeFrame();
    }

    /**
     * @return the progress bar
     */
    public JProgressBar getProgressBar() {
        return this.progressBar;
    }

    /**
     * The progress bar is placed in the center of the screen
     */
    private void placeFrame() {
        int horizontal = (int) ((Toolkit.getDefaultToolkit().getScreenSize()
                .getWidth() - this.getWidth()) / 2);
        int vertical = (int) ((Toolkit.getDefaultToolkit().getScreenSize()
                .getHeight() - this.getHeight()) / 2);
        this.setLocation(horizontal, vertical);
    }

    /**
     * The setting of the progress bar
     */
    private void prepareProgressBar() {
        this.progressBar = new JProgressBar(0, 99);
        this.progressBar.setStringPainted(true);
        this.pane.add(this.progressBar);
    }
}
